package one.stand.service.impl;

import cn.hutool.core.date.DateField;
import cn.hutool.core.util.StrUtil;
import com.google.common.collect.Lists;
import com.jmp.base.dto.*;
import com.jmp.feign.MessageFeign;
import com.jmp.service.crm.dto.OrderDto;
import com.jmp.service.crm.dto.OrderPayBackDto;
import com.jmp.service.crm.dto.OrderRefundDto;
import lombok.extern.slf4j.Slf4j;
import one.stand.advice.ResultEnum;
import one.stand.dto.Company2Dto;
import one.stand.dto.UserDto;
import one.stand.enums.LoginEnum;
import one.stand.enums.OrderStateEnum;
import one.stand.enums.RefundStateEnum;
import one.stand.event.OrderCompleteEvent;
import one.stand.mapper.*;
import one.stand.model.*;
import one.stand.service.CompanyBaseService;
import one.stand.service.GoodsBaseService;
import one.stand.service.OrdersService;
import one.stand.service.user.UserAdminService;
import one.stand.service.wx.WxPayService;
import one.stand.util.*;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @author
 */
@Service
@Slf4j
public class OrdersServiceImpl implements OrdersService {
    @Autowired
    private ApplicationContext applicationContext;
    @Autowired
    private MessageFeign messageFeign;

    @Autowired
    private WxPayService wxPayService;
    @Autowired
    private GoodsBaseService goodsBaseService;
    @Autowired
    private UserAdminService userAdminService;
    @Autowired
    private CompanyBaseService companyBaseService;

    @Autowired
    private AddressMapperExt addressMapperExt;
    @Autowired
    private OrdersMapperExt ordersMapperExt;
    @Autowired
    private RefundRecordMapper refundRecordMapper;
    @Autowired
    private OrderInfoMapperExt orderInfoMapperExt;
    @Autowired
    private GoodSpecMapperExt goodSpecMapperExt;
    @Autowired
    private ShopCartMapperExt shopCartMapperExt;

    @Override
    @Transactional
    public List<Integer> save(OrderSaveDto request) {
        Address address = null;
        if (request.isCheckFlag()) {//兼容小程序下单逻辑:支付时添加收货地址
            AssertUtil.nonNull(request.getAddressId(), ResultEnum.PARAM_CHECK, "请选择收货地址");
            address = addressMapperExt.selectByPrimaryKey(request.getAddressId());
            AssertUtil.isTrue(request.getUserId().equals(address.getUserId()), ResultEnum.PARAM_CHECK);
        }

        Integer total = 0;
        BigDecimal totalPrice = BigDecimal.ZERO;
        List<Integer> orderIds = Lists.newArrayList();

        for (OrderSaveDto.Supplier supplier : request.getSupplierList()) {
            OrderDto orderDto = orderSave(request.getUserId(), address, supplier, request.isCheckFlag());

            orderIds.add(orderDto.getOrderId());
            total = total + orderDto.getTotal();
            totalPrice = totalPrice.add(orderDto.getTotalPrice());
        }

        if (request.isCheckFlag()) {//兼容小程序下单逻辑,增加判断开关
            AssertUtil.isTrue(total.equals(request.getTotal()), ResultEnum.PARAM_CHECK, "总件数不一致");
        }
        if (request.isCheckFlag() || Objects.nonNull(request.getTotalPrice())) {//兼容小程序下单逻辑,增加判断开关
            AssertUtil.isTrue(totalPrice.compareTo(request.getTotalPrice()) == 0, ResultEnum.PARAM_CHECK, "总价不一致");
        }

        return orderIds;
    }

    @Override
    public void cancel(Integer orderId) {
        Orders orders = ordersMapperExt.selectByPrimaryKey(orderId);
        RequestContext.User optUser = RequestContextHolder.getRequestContext().getUser();
        AssertUtil.isTrue(orders.getUserId().equals(optUser.getUserId())
                || orders.getCompanyId().equals(optUser.getCompanyId()), ResultEnum.FAIL);

        String states = SqlUtil.in(Lists.newArrayList(OrderStateEnum.WAIT_PAYMENT.getCode()));
        int r = ordersMapperExt.updateState(orderId, OrderStateEnum.CANCEL.getCode(), states);
        AssertUtil.isTrue(r == 1, ResultEnum.FAIL);
    }

    @Override
    @Transactional
    public void send(Integer orderId, String deliveryCompany, String deliveryNo) {
        Orders ordersModel = ordersMapperExt.selectByPrimaryKey(orderId);
        RequestContext.User user = RequestContextHolder.getRequestContext().getUser();
        AssertUtil.isTrue(ordersModel.getCompanyId().equals(user.getCompanyId()), ResultEnum.NO_TOURIST);

        int i = ordersMapperExt.updateSend(orderId, OrderStateEnum.WAIT_DELIVER.getCode(), deliveryCompany, deliveryNo, OrderStateEnum.WAIT_RECEIVING.getCode());
        AssertUtil.isTrue(i == 1, ResultEnum.FAIL);
    }

    @Override
    @Transactional
    public void complete(Integer orderId) {
        Orders orders = ordersMapperExt.selectByPrimaryKey(orderId);
        AssertUtil.isTrue(orders.getUserId().equals(RequestContextHolder.getRequestContext().getUser().getUserId()), ResultEnum.FAIL);

        String states = SqlUtil.in(Lists.newArrayList(OrderStateEnum.WAIT_RECEIVING.getCode()));
        int r = ordersMapperExt.updateState(orderId, OrderStateEnum.COMPLETE.getCode(), states);
        AssertUtil.isTrue(r == 1, ResultEnum.FAIL);

        applicationContext.publishEvent(new OrderCompleteEvent(orderId));
    }

    /**
     * 微信退款回调 1
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public String backRefund(String notifyData) {
        log.info("退款回调：{}", notifyData);
        return wxPayService.fail();
    }

    @Override
    @Transactional
    public void payBack(OrderPayBackDto backDto) {
        for (Integer orderId : backDto.getOrderIds()) {
            // 修改订单
            int i = ordersMapperExt.updateState(orderId, OrderStateEnum.WAIT_DELIVER.getCode(), SqlUtil.in(Lists.newArrayList(OrderStateEnum.WAIT_PAYMENT.getCode())));
            AssertUtil.isTrue(i == 1, ResultEnum.PARAM_CHECK, "更新订单状态失败");

            Orders ordersSelect = ordersMapperExt.selectByPrimaryKey(orderId);

            Orders model = new Orders();
            model.setOrdersId(orderId);
            model.setTradeNo(backDto.getOutTradeNo());
            model.setPayPrice(ordersSelect.getOrderPrice());
            model.setPayTime(DateUtil.currentDate());
            ordersMapperExt.updateByPrimaryKeySelective(model);

            // 修改商品库存
            List<OrderInfo> list = orderInfoMapperExt.selectByOrderId(orderId);
            for (OrderInfo orderinfoModel : list) {
                int r = goodSpecMapperExt.updateGoodSpecNum(orderinfoModel.getSpecId(), orderinfoModel.getNum());
                AssertUtil.isTrue(r == 1, ResultEnum.PARAM_CHECK, "更新库存失败");
            }

            // 商家：订单状态改变 微信推送模板信息
//            List<OrderNoticeDto> listMap = ordersMapperExt.getSendTemplateInfo(new OrdersModel() {{
//                setOrdersId(entity.getOrdersId());
//                setType(1);
//            }});
//            listMap.forEach(entity1 -> {
//                {
//                    String[] fillData1 = {outTradeNo, wxNoticeEntity.getGoodsName(), MoneyUtil.getWithUnit(totalFee), OrderStateEnum.WAIT_DELIVER.getMessage(), entity1.getRemark()};
//                    MessagePushRequest pushRequest = MessagePushRequest.builder()
//                            .type(MessagePushType.ORDER_STATE_CRM)
//                            .toId(entity1.getCrmUserId())
//                            .fillData(fillData1)
//                            .build();
//                    messageFeign.push(pushRequest);
//                }
//            });
        }
    }

    @Override
    public void refundSuccess(OrderRefundDto refundDto) {
        // 修改订单状态
        Orders ordersModel = new Orders();
        ordersModel.setOrderState(OrderStateEnum.REFUND_SUCCESS.getCode());
        ordersModel.setRefundState(RefundStateEnum.REFUND_SUCCESS.getCode());
        ordersModel.setOrdersId(refundDto.getOrderId());
        ordersMapperExt.updateByPrimaryKeySelective(ordersModel);

        // 添加退款记录信息
        RefundRecordModel refundRecordModel = new RefundRecordModel();
        refundRecordModel.setOrdersId(refundDto.getOrderId());
        refundRecordModel.setOrdersNo(refundDto.getTradeNo());
        refundRecordModel.setRefundNo(refundDto.getRefundNo());
        refundRecordModel.setTotalFee(String.valueOf(refundDto.getTotalFee()));
        refundRecordModel.setRefundFee(String.valueOf(refundDto.getTotalFee()));
        refundRecordModel.setRefundStatus("SUCCESS");
        refundRecordModel.setCreateTime(DateUtil.currentDate());
        refundRecordMapper.insertSelective(refundRecordModel);

        // 微信推送模板 订单状态改变消息
        Orders orders = ordersMapperExt.selectByPrimaryKey(refundDto.getOrderId());
        Company2Dto company2Dto = companyBaseService.get2(orders.getCompanyId());
        List<OrderInfo> list = orderInfoMapperExt.selectByOrderId(orders.getOrdersId());
        String goodsNames = list.stream().map(OrderInfo::getGoodsName).collect(Collectors.joining(StrUtil.COMMA));

        String[] fillData = {orders.getOrdersNo(), StrUtil.maxLength(goodsNames, 20),
                MoneyUtil.getWithUnit(refundDto.getTotalFee()), OrderStateEnum.REFUND_SUCCESS.getMessage(), orders.getAddressPhone()};
        MessageWxServiceRequest messageDto = MessageWxServiceRequest.builder()
                .noticeEnums(MessageWxNoticeEnums.ORDER_STATE_USER)
                .toUserId(orders.getUserId())
                .accountType(LoginEnum.USER)
                .fillData(fillData)
                .build();
        messageFeign.wxService(messageDto);
    }

    @Override
    public void remindSend(Integer orderId) {
        Orders orders = ordersMapperExt.selectByPrimaryKey(orderId);
        AssertUtil.isTrue(orders.getOrderState().equals(OrderStateEnum.WAIT_DELIVER.getCode()), ResultEnum.FAIL);
        AssertUtil.isTrue(orders.getUserId().equals(RequestContextHolder.getRequestContext().getUser().getUserId()), ResultEnum.FAIL);


        // 推送 发货提醒消息
        Company2Dto company2Dto = companyBaseService.get2(orders.getCompanyId());
        List<OrderInfo> list = orderInfoMapperExt.selectByOrderId(orderId);
        String goodsNames = list.stream().map(OrderInfo::getGoodsName).collect(Collectors.joining(StrUtil.COMMA));
        String[] fillData = {orders.getOrdersNo(),
                orders.getRemark(), StrUtil.maxLength(goodsNames, 20),
                MoneyUtil.getWithUnit(orders.getOrderPrice())};
        MessagePushRequest pushRequest = MessagePushRequest.builder()
                .type(MessagePushType.ORDER_DELIVER)
                .toId(company2Dto.getUserId())
                .fillData(fillData)
                .build();
        messageFeign.push(pushRequest);
    }

    @Override
    @Transactional
    public void refundApply(Integer orderId, String refundRemark) {
        Orders orders = ordersMapperExt.selectByPrimaryKey(orderId);
        AssertUtil.isTrue(orders.getUserId().equals(RequestContextHolder.getRequestContext().getUser().getUserId()), ResultEnum.FAIL);

        String orderSates = SqlUtil.in(Lists.newArrayList(OrderStateEnum.WAIT_DELIVER.getCode(), OrderStateEnum.WAIT_RECEIVING.getCode()));
        int r = ordersMapperExt.updateRefund(orderId, RefundStateEnum.REFUND_APPLY.getCode(), refundRemark, orderSates, RefundStateEnum.NO_REFUND.getCode());
        AssertUtil.isTrue(r == 1, ResultEnum.FAIL);

        // 微信推送 退款申请消息
        Company2Dto company2Dto = companyBaseService.get2(orders.getCompanyId());
        List<OrderInfo> list = orderInfoMapperExt.selectByOrderId(orderId);
        String goodsNames = list.stream().map(OrderInfo::getGoodsName).collect(Collectors.joining(StrUtil.COMMA));
        String[] fillData = {orders.getOrdersNo(), DateUtil.getDay(), StrUtil.maxLength(goodsNames, 20),
                MoneyUtil.getWithUnit(orders.getOrderPrice()), StringUtils.defaultIfBlank(refundRemark, "无")};
        MessagePushRequest pushRequest = MessagePushRequest.builder()
                .type(MessagePushType.REFUND_APPLY)
                .toId(company2Dto.getUserId())
                .fillData(fillData)
                .build();
        messageFeign.push(pushRequest);
    }

    @Override
    public void refundApplyCancel(Integer orderId) {
        Orders orders = ordersMapperExt.selectByPrimaryKey(orderId);
        AssertUtil.isTrue(orders.getUserId().equals(RequestContextHolder.getRequestContext().getUser().getUserId()), ResultEnum.FAIL);

        int r = ordersMapperExt.updateRefund(orderId, RefundStateEnum.NO_REFUND.getCode(), null, null, RefundStateEnum.REFUND_APPLY.getCode());
        AssertUtil.isTrue(r == 1, ResultEnum.FAIL);
    }

    @Override
    public void timeout() {
        Date payLimitDate = cn.hutool.core.date.DateUtil.offset(new Date(), DateField.MINUTE, -TIMEOUT);
        List<Integer> ids = ordersMapperExt.selectTimeout(payLimitDate);
        if (OneListUtil.isEmpty(ids)) {
            return;
        }
        String inStates = SqlUtil.in(Lists.newArrayList(OrderStateEnum.WAIT_PAYMENT.getCode()));
        for (Integer id : ids) {
            ordersMapperExt.updateState(id, OrderStateEnum.BE_OVERDUE.getCode(), inStates);
        }
    }

    private OrderDto orderSave(Integer userId, Address address, OrderSaveDto.Supplier supplier, boolean checkFlag) {
        Date now = new Date();
        Integer total = 0;
        Integer totalPrice = 0;
        StringBuilder goodsName = new StringBuilder(StringUtils.EMPTY);

        OrderInfo model;
        List<OrderInfo> infoList = Lists.newArrayList();
        for (OrderSaveDto.Goods infoRequest : supplier.getGoodsList()) {
            // 判断商品规格库存
            GoodSpec goodSpecModel = goodSpecMapperExt.selectByPrimaryKey(infoRequest.getSpecId());
            AssertUtil.nonNull(goodSpecModel, ResultEnum.FAIL, "商品规格失效，请重新筛选！");
            AssertUtil.isTrue(goodSpecModel.getSpecNum() >= infoRequest.getNum(), ResultEnum.FAIL, "库存不足！");
            Goods goods = goodsBaseService.getOn(goodSpecModel.getGoodsId());
            AssertUtil.nonNull(goods, ResultEnum.FAIL, "商品已下架");

            model = new OrderInfo();
            model.setGoodsId(goodSpecModel.getGoodsId());
            model.setSpecId(goodSpecModel.getSpecId());
            model.setGoodsName(goods.getGoodsName());
            model.setSpecName(goodSpecModel.getSpecName() + " " + goodSpecModel.getSpecAttribute());
            model.setNum(infoRequest.getNum());
            model.setPrice(goodSpecModel.getPrice());
            model.setAllPrice(goodSpecModel.getPrice() * infoRequest.getNum());// 商品总价
            model.setCardId(infoRequest.getCardId());
            model.setForwardId(infoRequest.getForwardId());
            model.setGroupId(infoRequest.getGroupId());
            infoList.add(model);

            total = total + model.getNum();
            totalPrice = totalPrice + model.getAllPrice();
            goodsName.append(",").append(goodSpecModel.getSpecName());

            if (Objects.nonNull(infoRequest.getShopCartId())) {
                shopCartMapperExt.deleteByPrimaryKey(infoRequest.getShopCartId());
            }
        }

        if (checkFlag) {
            AssertUtil.isTrue(supplier.getTotalPrice().compareTo(MoneyUtil.getMoney(totalPrice)) == 0, ResultEnum.FAIL, "订单金额不一致");
        }

        // 在添加订单表
        Orders ordersModel = new Orders();
        ordersModel.setUserId(userId);// 用户ID
        ordersModel.setCompanyId(supplier.getCompanyId());
        if (Objects.nonNull(address)) {
            ordersModel.setAddressId(address.getAddressId());
            ordersModel.setAddressName(address.getReceiveName());
            ordersModel.setAddressPhone(address.getReceivePhone());
            ordersModel.setAddressDetail(StrUtil.concat(true, address.getLocationAddress(), address.getDetailedAddress()));
        }
        ordersModel.setOrdersNo(getOrderNo()); // 订单号
        ordersModel.setOrderPrice(totalPrice);// 订单总金额
        ordersModel.setRemark(supplier.getRemark());
        ordersModel.setPayType(1);// 默认线上支付
        ordersModel.setOrderState(OrderStateEnum.WAIT_PAYMENT.getCode());// 订单状态（1待付款，2待发货，3待收货，4已完成，5交易取消，6退款成功）
        ordersModel.setRefundState(RefundStateEnum.NO_REFUND.getCode());// 1未申请，2退款申请中，3退款成功
        ordersModel.setDeliveryType(1);// 配送方式
        ordersModel.setDeliveryState(1);// 配送状态
        ordersModel.setCreateTime(now);
        int r = ordersMapperExt.insertSelective(ordersModel);
        AssertUtil.isTrue(r > 0, ResultEnum.FAIL);

        // 添加订单明细表
        for (OrderInfo info : infoList) {
            info.setOrdersId(ordersModel.getOrdersId());// 订单id
            info.setCreateTime(now);
            orderInfoMapperExt.insertSelective(info);
        }

        // 发送新订单微信推送提醒
        UserDto user = userAdminService.get(userId);
        Company2Dto company = companyBaseService.get2(supplier.getCompanyId());
        String[] fillData = {ordersModel.getOrdersNo(), StrUtil.maxLength(goodsName.substring(1), 20), company.getCompanyName(),
                MoneyUtil.getWithUnit(totalPrice), DateUtil.getDay(), user.getName()};
        MessagePushRequest pushRequest = MessagePushRequest.builder()
                .type(MessagePushType.NEW_ORDER)
                .toId(company.getUserId())
                .fillData(fillData)
                .build();
        messageFeign.push(pushRequest);

        return OrderDto.builder()
                .orderId(ordersModel.getOrdersId())
                .total(total)
                .totalPrice(MoneyUtil.getMoney(totalPrice))
                .build();
    }

    /**
     * 根据时间戳生产订单编号
     */
    private static String getOrderNo() {
        return "YL" + System.currentTimeMillis() + "" + (int) (1 + Math.random() * (9999));
    }
}
